/*
 * This file belongs to the Galois project, a C++ library for exploiting parallelism.
 * The code is being released under the terms of the 3-Clause BSD License (a
 * copy is located in LICENSE.txt at the top-level directory).
 *
 * Copyright (C) 2018, The University of Texas at Austin. All rights reserved.
 * UNIVERSITY EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES CONCERNING THIS
 * SOFTWARE AND DOCUMENTATION, INCLUDING ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR ANY PARTICULAR PURPOSE, NON-INFRINGEMENT AND WARRANTIES OF
 * PERFORMANCE, AND ANY WARRANTY THAT MIGHT OTHERWISE ARISE FROM COURSE OF
 * DEALING OR USAGE OF TRADE.  NO WARRANTY IS EITHER EXPRESS OR IMPLIED WITH
 * RESPECT TO THE USE OF THE SOFTWARE OR DOCUMENTATION. Under no circumstances
 * shall University be liable for incidental, special, indirect, direct or
 * consequential damages or loss of profits, interruption of business, or
 * related expenses which may arise from use of Software or Documentation,
 * including but not limited to those resulting from defects in Software and/or
 * Documentation, or loss or inaccuracy of data of any kind.
 */

#include "galois/Galois.h"
#include "galois/ParallelSTL/ParallelSTL.h"
#include "galois/graphs/Bag.h"
#include "galois/Timer.h"

#include "llvm/Support/CommandLine.h"
#include "Lonestar/BoilerPlate.h"

#include "galois/worklists/WorkListAlt.h"
#include "galois/worklists/WorkListDebug.h"

#include "galois/graphs/Graph3.h"
#include "galois/runtime/DistSupport.h"

#include <cassert>
#include <stdlib.h>

#include "Edge.h"
#include "galois/runtime/Serialize.h"

#include "galois/runtime/Context.h"

#include <vector>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <cassert>

struct node_data {

  int data;

  typedef int tt_is_copyable;
};

// dummy graph3
typedef galois::graphs::ThirdGraph<int, void, galois::graphs::EdgeDirection::Un>
    Graph;
typedef Graph::NodeHandle GNode;
typedef typename Graph::pointer Graphp;

namespace cll = llvm::cl;

static const char* name = "Delaunay Mesh Refinement";
static const char* desc = "Refines a Delaunay triangulation mesh such that no "
                          "angle in the mesh is less than 30 degrees\n";
static const char* url = "delaunay_mesh_refinement";

static cll::opt<std::string> filename(cll::Positional,
                                      cll::desc("<input file>"), cll::Required);

// dummy for_each
/*
struct initialize {

  Graphp g;
  void static go(Graphp g, std::vector<int>& elements) {
    galois::for_each(elements.begin(), elements.end(), initialize{g},
galois::loopname("initialize"));
  }

  void operator() (node_data& item, galois::UserContext<node_data>& cnx) {
    GNode n = g->createNode(item);
    g->addNode(n);
  }

  typedef int tt_is_copyable;
};

*/

struct initialize : public galois::runtime::Lockable {
  Graphp g;
  initialize() {}
  initialize(Graphp _g) : g(_g) {}

  void operator()(int& item, galois::UserContext<int>& cnx) {
    GNode n = g->createNode(item);
    g->addNode(n);
  }
  // serialization functions
  typedef int tt_has_serialize;
  void serialize(galois::runtime::SerializeBuffer& s) const {
    gSerialize(s, g);
  }
  void deserialize(galois::runtime::DeSerializeBuffer& s) {
    gDeserialize(s, g);
  }
};

struct Point;
typedef galois::runtime::PerThreadDist<Point> DistPoint;
typedef galois::runtime::gptr<Point> PtrPoint;

struct Point : galois::runtime::Lockable {

  typedef int tt_is_copyable;

  using Base = galois::runtime::Lockable;

  int x;
  int y;

  Point() : Base(), x(11), y(22) {}

  Point(int _x, int _y) : Base(), x(_x), y(_y) {}

  Point(DistPoint) : Base(), x(10), y(20) {}

  Point(DistPoint, galois::runtime::DeSerializeBuffer& buf)
      : Base(), x(100), y(200) {}

  void getInitData(galois::runtime::SerializeBuffer& buf) {}
};

struct OnEachFunc {

  DistPoint dp;

  OnEachFunc(void) : dp() {}

  OnEachFunc(DistPoint _dp) : dp(_dp) {}

  typedef int tt_is_copyable;

  void operator()(unsigned tid, unsigned numT) {
    // assert (dp != nullptr);

    PtrPoint p = dp.local();

    std::printf("In on_each: Host=%u, Thread=%u, x=%d, y=%d\n",
                galois::runtime::NetworkInterface::ID, tid, p->x, p->y);
  }
};

int main(int argc, char** argv) {

  LonestarStart(argc, argv, name, desc, url);
  galois::StatManager statManager;

  galois::runtime::getSystemNetworkInterface().start();

  DistPoint dp = DistPoint::allocate();

  PtrPoint p = dp.local();
  std::printf("After allocate: Host=%u, Thread=%u, x=%d, y=%d\n",
              galois::runtime::NetworkInterface::ID, 0, p->x, p->y);

  galois::on_each(OnEachFunc{dp}, "test-loop");

  // Graphp g;
  // g = Graph::allocate();

  // std::vector<int> vec_items;
  // for (int i = 0; i < 100; i++) {
  //   vec_items.push_back(i);
  // }
  // for (auto ii : vec_items) {
  // std::cout << ii.data << "\n";
  // }
  // galois::for_each(vec_items.begin(), vec_items.end(),initialize(g),
  // galois::loopname("initializing"));//,
  // galois::wl<galois::worklists::StableIterator<>>());

  galois::runtime::getSystemNetworkInterface().terminate();
}
